package com.tuanzi.loan.business.service.schedule;

import com.tuanzi.loan.business.constants.sms.SmsVoiceSendTaskStatus;
import com.tuanzi.loan.business.entity.sms.*;
import com.tuanzi.loan.business.service.sms.SmsCalculateTaskService;
import com.tuanzi.loan.business.service.sms.SmsSendTaskService;
import com.tuanzi.loan.business.service.sms.SmsVoiceSendTaskService;
import com.tuanzi.loan.core.aspect.Debug;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.joda.time.DateTime;
import org.joda.time.Minutes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Ray 2017/09/21
 */

@Debug
@Slf4j
@Service
@Transactional
public class SmsScheduler {

	@Autowired
	private SmsSendTaskService smsSendTaskService;
	@Autowired
	private SmsVoiceSendTaskService smsVoiceSendTaskService;
	@Autowired
	private SmsCalculateTaskService smsCalculateTaskService;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	private final static String SMS_SEND_TASK_KEY = "sms-send-task:%s";

	@Scheduled(cron = "${cron.sms-calculate-task}")
	public void calculateCount() {

		if (smsCalculateTaskService.countByStatus(SmsCalculateTaskStatus.CALCULATING) > 0) {
			return;
		}

		SmsCalculateTask smsCalculateTask = smsCalculateTaskService.findTopByStatusAndCalculateTimeBeforeOrderByCalculateTime(
				SmsCalculateTaskStatus.READY_CALCULATE, new Date());

		if (smsCalculateTask == null) {
			return;
		}

		smsCalculateTaskService.updateStatusWithoutTransactional(smsCalculateTask, SmsCalculateTaskStatus.CALCULATING);
		smsCalculateTaskService.calculateSmsCount(smsCalculateTask);
	}

	@Scheduled(cron = "${cron.sms-send-task}")
	@Transactional(propagation= Propagation.NOT_SUPPORTED)
	public void sendSms() {

		if (smsSendTaskService.countByStatus(SmsSendTaskStatus.SENDING) > 0) {
			return;
		}

		SmsSendTask smsSendTask = smsSendTaskService.findTopOneByStatusAndExecuteTimeBefore(SmsSendTaskStatus.READY_SEND, new Date());

		if (smsSendTask == null) {
			return;
		}

		// 避免读写延时
		// 增加缓存来判断任务是否执行过，防止重复执行
		if (!stringRedisTemplate.hasKey(String.format(SMS_SEND_TASK_KEY, smsSendTask.getId()))) {
			stringRedisTemplate.opsForValue().set(String.format(SMS_SEND_TASK_KEY, smsSendTask.getId()), "1", 7, TimeUnit.DAYS);
		    smsSendTask.setSendTime(new Date());
		    smsSendTaskService.updateStatusWithoutTransactional(smsSendTask, SmsSendTaskStatus.SENDING);
		    smsSendTaskService.sendSms(smsSendTask);
		}
	}


	@Scheduled(cron = "${cron.sms-voice-send-task}")
	@Transactional(propagation= Propagation.NOT_SUPPORTED)
	public void sendVoiceSms(){
		if(smsVoiceSendTaskService.countByStatus(SmsVoiceSendTaskStatus.SENDING) > 0){
			return;
		}

		SmsVoiceSendTask smsVoiceSendTask = smsVoiceSendTaskService.findTopOneByStatusAndExecuteTimeBefore(SmsVoiceSendTaskStatus.READY_SEND, new Date());
		if(smsVoiceSendTask == null){
			return;
		}
		smsVoiceSendTaskService.updateStatusWithoutTransactional(smsVoiceSendTask, SmsVoiceSendTaskStatus.SENDING);
		smsVoiceSendTaskService.sendVoiceSms(smsVoiceSendTask);

	}

	@Scheduled(cron = "${cron.suspense-sms-send-timeout-task}")
	public void suspenseSmsSendTimeOutTasks() {
		List<SmsSendTask> sendingTask = smsSendTaskService.findByStatus(SmsSendTaskStatus.SENDING);
		if (CollectionUtils.isEmpty(sendingTask)){
			return ;
		}
		for (SmsSendTask smsSendTask : sendingTask){
			if (smsSendTask.getSendTime() != null){
				if (Minutes.minutesBetween(new DateTime(smsSendTask.getSendTime()), DateTime.now()).getMinutes() > 15) {//发送超过15分钟还没有改状态
					smsSendTaskService.updateStatusWithoutTransactional(smsSendTask, SmsSendTaskStatus.HANG_UP);
				}
			}
		}
	}

	@Scheduled(cron = "${cron.suspense-sms-calculate-task}")
	public void suspenseSmsCalculateTasks() {
		if (smsCalculateTaskService.countByStatus(SmsCalculateTaskStatus.CALCULATING) == 0) {
			return;
		}

		SmsCalculateTask smsCalculateTask = smsCalculateTaskService.findTopOneByStatus(SmsCalculateTaskStatus.CALCULATING);

		if (smsCalculateTask == null) {
			return;
		}

		if (Minutes.minutesBetween(new DateTime(smsCalculateTask.getCalculateTime()), DateTime.now()).getMinutes() > 15) {
			smsCalculateTask.setStatus(SmsCalculateTaskStatus.SUSPENSE);
			smsCalculateTaskService.saveOrUpdate(smsCalculateTask);
		}
	}

	@Scheduled(cron = "${cron.active-sms-calculate-task}")
	public void activeSmsCalculateTasks() {
		if (smsCalculateTaskService.countByStatus(SmsCalculateTaskStatus.SUSPENSE) == 0 || smsCalculateTaskService.countByStatus(SmsCalculateTaskStatus.READY_CALCULATE) > 0) {
			return;
		}

		SmsCalculateTask smsCalculateTask = smsCalculateTaskService.findTopOneByStatus(SmsCalculateTaskStatus.SUSPENSE);

		if (smsCalculateTask == null) {
			return;
		}
		smsCalculateTask.setStatus(SmsCalculateTaskStatus.READY_CALCULATE);
		smsCalculateTaskService.saveOrUpdate(smsCalculateTask);
	}
}
